﻿package com.sos.ui {
	
	
	import com.greensock.data.TweenMaxVars;
	import com.greensock.easing.*;
	import com.greensock.events.TweenEvent;
	import com.greensock.TimelineMax;
	import com.greensock.TweenMax;
	import com.sos.core.game.engine.GameEngine;
	import com.sos.core.game.events.GameEndEvent;
	import com.sos.core.game.events.GameEvent;
	import com.sos.core.game.events.GamePhaseEvent;
	import com.sos.core.game.GameAction;
	import com.sos.core.game.GameActionCard;
	import com.sos.core.game.GameActionRole;
	import com.sos.core.game.GameActionTarget;
	import com.sos.core.game.GameEndCause;
	import com.sos.core.game.GamePhase;
	import com.sos.core.game.GameRole;
	import com.sos.core.game.GameStatus;
	import com.sos.core.game.GameTurn;
	import com.sos.core.game.requests.GameRequest;
	import com.sos.core.game.requests.GameRequestDiscardParams;
	import com.sos.core.game.requests.GameRequestPlayParams;
	import com.sos.core.game.requests.GameRequestSubstituteParams;
	import com.sos.core.Position;
	import com.sos.core.TargetType;
	import com.sos.logging.Logger;
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	
	public class PlayArea extends MovieClip {
		
		public var engine:GameEngine;
		public var nextTurnAvailable:Boolean = false;
		public var gameIsOver:Boolean = false;
		public var playerSkipsSolvePhase:Boolean = false;
		public var playerSkipsLog:Boolean = false;
		public var currentStatus:GameStatus;
		public var clientSide:String;
		public var oppSide:String;
		public var ballHandler:String;
		public var homeTeamName:String;
		public var awayTeamName:String;
		public var maxPlayables:Number = 7;
		public var activePlayers:Array = new Array();
		public var clientRole:GameRole;
		public var endCause:GameEndCause;
		public var timeline:TimelineMax;
		
		//Card Lists and counters
		public var handCardList:Dictionary = new Dictionary(); //List of cards in logged user's hand
		public var handCounter:Number = 0; 
		public var cardList:Dictionary = new Dictionary(); //Full list of action cards instanced from the beggining of the match
		public var fullCardCounter:Number = 0;
		public var discardCounter:Number = 0; // Number of cards queued for discard
		public var discardList:Dictionary = new Dictionary(); // Cards queued for discard
		public var playedList:Array = new Array(); // Cards queued for play
		public var playCounter:Number = 0; // Number of cards queued for play
		public var subList:Dictionary = new Dictionary(); //list of substitutions
		public var maxSubstitutions:uint = 2;
		public var subCounter:uint = 0;
		public var effectList:Array = new Array(); // List of all active effects
		
		//Client variables
		public var password:String;
		
		//Targeting variables
		public var targetingCardId:String = '';
		public var targetModeActive:Boolean = false;
		public var roundActionTarget:String = '';
		public var roundAction:String = '';
		public var passTargets:Array = new Array();
		public var dribbleTargets:Array = new Array();
		
		//UI Elements
		public var ball:Ball;
		public var imgGoal:MovieClip;
		public var imgScored:MovieClip;
		public var endGameScreen:EndGameScreen;
		public var playButton:PlayButton;
		public var containerList:Array = new Array();
		public var arrowMc:MovieClip;
		public var frontObjects:Array = new Array();
		public var overlay:CardSelectionOverlay;
		public var roundViewer:RoundViewer;
		public var solveOverlay:SolveOverlay;
		public var fieldMc:Field;
		
		public function PlayArea() {
			Logger.debug("UI > Creating PlayArea");
						
			homeGraveOverlay.visible = false;
			awayGraveOverlay.visible = false;
			endGameScreen.visible = false;
			imgGoal.visible = false;
			imgScored.visible = false;
			playMenu.visible = false;
			playButton.visible = false;
			logBox.visible = false;
		}
		
		/********************************************************************* INIT FUNCTION *************************************************************/
		
		public function init(engine:GameEngine) {
			Logger.debug("UI > Init PlayArea");
			
			this.engine = engine;
			currentStatus = GameStatus.PLAY;
			clientSide = engine.game.side.name;
			if (clientSide == 'home') {
				oppSide = 'away';
			}
			else {
				oppSide = 'home';
			}
			maxPlayables = engine.game.playerTeam.cards.maxPlayable;
			clientRole = engine.game.playerTeam.role;
			timeline = new TimelineMax(new TweenMaxVars().onCompleteListener(fieldReadyHandler));
			
			
			ball = new Ball();
			if (engine.game.isPlayerAttacking) {
				ballHandler = engine.game.playerActivePlayerCard.instanceId.toString();
				updateActionTargets();
			}
			else {
				ballHandler = engine.game.opponentActivePlayerCard.instanceId.toString();
			}
			activePlayers[clientSide] = engine.game.playerActivePlayerCard.instanceId.toString();
			activePlayers[oppSide] = engine.game.opponentActivePlayerCard.instanceId.toString();
			homeTeamName = engine.game.homeTeam.name;
			awayTeamName = engine.game.awayTeam.name;
			
			scoreboard.roundCounterBox.text = "Round " + engine.game.turn;
			scoreboard.homeScoreBox.text = engine.game.homeTeam.score.toString();
			scoreboard.awayScoreBox.text = engine.game.awayTeam.score.toString();
			
			scoreboard.homeTeamNameBox.text = homeTeamName;
			
			scoreboard.awayTeamNameBox.text = awayTeamName;
			
			homeHandMC.numBox.text = engine.game.homeTeam.cards.cardCount;
			awayHandMC.numBox.text = engine.game.awayTeam.cards.cardCount;
			
			homeDeckMC.numBox.text = engine.game.homeTeam.cards.deckCardCount;
			awayDeckMC.numBox.text = engine.game.awayTeam.cards.deckCardCount;
			
			/******************** Initializing Field MovieClip *******************/
			
			fieldMc.init(this);
			fieldMc.playerList[activePlayers[clientSide]].setAsActive();
			fieldMc.playerList[ballHandler].setAsBallHandler(ball);
			
			/******************** Field MovieClip Ready *******************/
			
			/******************** Creating hand ActionCards *******************/
			
			var gac:GameActionCard;
			var ac:ActionCardClip;
			for each (gac in engine.game.playerTeam.cards.hand) {
				
				ac = new ActionCardClip(gac, this, i);
				addCardToHand(ac);
				timeline.insert(animateCardToHand(ac));
			}
			
			var acData:Object;
			var i:Number;
			
			/******************** hand ActionCards Ready *******************/
			
			/******************** Initializing Graveyards *******************/
			
			homeGraveMC.numBox.text = engine.game.homeTeam.cards.graveyardCardCount.toString();
			awayGraveMC.numBox.text = engine.game.opponentTeam.cards.graveyardCardCount.toString();
			//homeGraveMC.addEventListener(MouseEvent.CLICK, toggleHomeGraveOverlay, false, 0, true);
			//awayGraveMC.addEventListener(MouseEvent.CLICK, toggleAwayGraveOverlay, false, 0, true);
			homeGraveOverlay.graveTeamName.text = homeTeamName;
			awayGraveOverlay.graveTeamName.text = awayTeamName;
			/*
			for each (gac in engine.game.playerTeam.cards.graveyard) {
				//trace(gac.name);
				ac = new ActionCardClip(gac, this, i, 'grave');
				addCardToGrave(clientSide, ac);
			}
			*/
			//TODO: add opponent graveyard
			
			/******************** Graveyards Ready *******************/
			
			/******************** Adding Card Selection Overlay *******************/
			
			overlay = new CardSelectionOverlay();
			//solveOverlay =  new SolveOverlay();
			solveOverlay.x = 172;
			solveOverlay.y = 785;
			addChild(solveOverlay);
			
			timeline.play();
			
			//addEventListener(TweenEvent.MOTION_FINISH, fieldReadyHandler, false, 0, true);
		}
		
		/********************************************************************* END INIT FUNCTION *************************************************************/
		
		/********************************************************************* LISTENER FUNCTIONS *************************************************************/
		
		private function playButtonClickHandler(e:MouseEvent):void {
			Logger.debug("UI > PlayButton Clicked");
			var request:GameRequest;
			
			switch (currentStatus) {
				case GameStatus.PLAY:
					var params:GameRequestPlayParams = engine.createRequestParams(GamePhase.PLAY, password) as GameRequestPlayParams;
					var actionTarget:GameActionTarget;
					params.role   = engine.game.isPlayerAttacking ? GameActionRole.ATTACKER : GameActionRole.DEFENDER; 
					
					for (var i:uint = 1; i <= playCounter; i++) {
						Logger.debug("UI > Adding card " + playedList[i].gameActionCard.name);
						if (playedList[i].gameActionCard.hasTargetInput) {
							actionTarget = new GameActionTarget(playedList[i].gameActionCard.targetInput.type);
							actionTarget.addParam(playedList[i].targetParamName, playedList[i].targetId);
							params.addCard(playedList[i].gameActionCard, actionTarget);
						}
						else
							params.addCard(playedList[i].gameActionCard, new GameActionTarget(TargetType.NONE));
					}
					if (params.role == GameActionRole.ATTACKER) {
						if (roundAction == '') {
							logBox.dbgTextBox.text = "You must select an action for this round" + logBox.dbgTextBox.text;
							return;
						}
						else if (((params.action == GameAction.DRIBBLE) || (params.action == GameAction.PASS)) && (roundActionTarget == ''))  {
							logBox.dbgTextBox.text = "You must select a target for this round's action" + logBox.dbgTextBox.text;
							return;
						}
						else {
							params.action = GameAction.getByName(roundAction);
							if ((params.action == GameAction.DRIBBLE) || (params.action == GameAction.PASS))
								params.target = Position.getBySign(roundActionTarget);
							
						}
					}
					
					// Request creation
					request = engine.createRequest(GamePhase.PLAY, params);
					// Execute the request
					engine.execute(request);
					
					break;
				case GameStatus.DISCARD:
					var discardParams:GameRequestDiscardParams = engine.createRequestParams(GamePhase.DISCARD, password) as GameRequestDiscardParams;
					var ac:ActionCardClip;
					for each (ac in discardList) {
						discardParams.add(ac.gameActionCard);
					}
					Logger.debug("UI > Discarding");
					// Request creation
					request = engine.createRequest(GamePhase.DISCARD, discardParams);
					// Execute the request
					engine.execute(request);
					break;
				case GameStatus.SUBSTITUTION:
					var subParams:GameRequestSubstituteParams = engine.createRequestParams(GamePhase.SUBSTITUTE, password) as GameRequestSubstituteParams;
					
					Logger.debug("UI > PLAYAREA > Subbing players");
					
					for (var posSign in subList) {
						Logger.debug("UI > PLAYAREA > Subbing out " + posSign);
						subParams.add(Position.getBySign(posSign));
					}
					// Request creation
					request = engine.createRequest(GamePhase.SUBSTITUTE, subParams);
					// Execute the request
					engine.execute(request);
					
					break;
				case GameStatus.RESOLVE_PLAY:
					if (playerSkipsLog) {
						playerSkipsSolvePhase = true;
					}
					else {
						playerSkipsLog = true;
					}
					updateUIStatus();
					break;
				default:
					Logger.debug("UI > Nothing to do here");
					break;
			}
		}
		
		private function phaseChangeHandler(e:GamePhaseEvent) {
			Logger.debug("UI > Phase change event: entering" + e.phase.name + "phase");
			updateUIStatus();
		}
		
		private function endGameHandler(e:GameEndEvent) {
			engine.removeEventListener(GameEvent.EVENT_GAME_NEXT_TURN_PHASE, phaseChangeHandler);
			engine.removeEventListener(GameEvent.EVENT_GAME_END, endGameHandler);
			
			gameIsOver = true;
			endCause = e.cause;
			//Logger.debug("UI > PlayArea > GAME OVER");
			if (currentStatus == GameStatus.RESOLVE_PLAY) {
				
			}
			else {
				endGame();
			}
		}
		
		private function fieldReadyHandler(e:TweenEvent):void {
			fieldMc.activate();
			timeline = new TimelineMax();
			this.attachMenu();
			if (engine.game.status != GameStatus.PLAY) {
				updateUIStatus();
			}
			playButton.visible = true;
			playButton.buttonMode = true;
			playButton.useHandCursor = true;
			playButton.mouseChildren = false;
			playButton.addEventListener(MouseEvent.CLICK, playButtonClickHandler, false, 0, true);
			engine.addEventListener(GameEvent.EVENT_GAME_NEXT_TURN_PHASE, phaseChangeHandler, false, 0, true);
			engine.addEventListener(GameEvent.EVENT_GAME_END, endGameHandler, false, 0, true);
		}
		/********************************************************************* END LISTENER FUNCTIONS *************************************************************/
		
		/********************************************************************* CARD HANDLING FUNCTIONS *************************************************************/
		
		public function addCardToGame(ac:ActionCardClip) {
			if (!cardList[ac.instanceId]) {
				fullCardCounter++;
				cardList[ac.instanceId] = ac;
				//trace("Added card " + ac.name + " (" + ac.instanceId + ") to game");
			}
			/*
			else
				trace("Card " + ac.name + " (" + ac.instanceId + ") was already in the game");
				*/
		}
		
		public function removeCardFromGame(ac:ActionCardClip) {
			fullCardCounter--;
			//cardList.splice(ac.instanceId, 1);
			delete cardList[ac.instanceId];
		}
		
		public function addCardToHand(ac:ActionCardClip, showGlow:Boolean = false) {
			handCounter++;
			handCardList[ac.instanceId] = ac;
			addCardToGame(ac);
			ac.cardOrder = handCounter;
			addChild(ac);
			this.setChildIndex(ac, handCounter);
			ac.x = (handCounter - 1)*70 + this.ac1.x;
			ac.y = this.ac1.y;
			
			ac.addToHand(showGlow);
		}
		
		public function removeCardFromHand(ac:ActionCardClip) {
			removeChild(ac);
			//handCardList.splice(ac.instanceId, 1);
			Logger.debug("UI > removeCardFromHand > removing " + handCardList[ac.instanceId].name);
			delete handCardList[ac.instanceId];
			handCounter--;
		}
		
		public function removeCardFromGrave(side:String, instanceId:String) {
			if (side == "home") {
				homeGraveOverlay.removeCard(instanceId);
				homeGraveMC.numBox.text = homeGraveOverlay.cardCount;
			}
			else {
				awayGraveOverlay.removeCard(instanceId);
				awayGraveMC.numBox.text = awayGraveOverlay.cardCount;
			}
		}
		
		public function addCardToGrave(side:String, ac:ActionCardClip) {
			addCardToGame(ac);
			if (side == "home") {
				homeGraveOverlay.addCard(ac);
				homeGraveMC.numBox.text = homeGraveOverlay.cardCount;
			}
			else {
				awayGraveOverlay.addCard(ac);
				awayGraveMC.numBox.text = awayGraveOverlay.cardCount;
			}
		}
		
		/********************************************************************* END CARD HANDLING FUNCTIONS *************************************************************/
		
		/********************************************************************* EFFECT HANDLING FUNCTIONS *************************************************************/
		
		public function addEffect(effect:Effect) {
			
			for each (var effectTarget:String in effect.targetList) {
				fieldMc.playerList[effectTarget].effectBox.addEffect(effect);
			}
			effectList[effect.effectId] = effect;
		}
		
		public function removeEffectFromPlayer(effectId:uint, playerId:String) {
			
			var effect:Effect = effectList[effectId];
			
			fieldMc.playerList[playerId].effectBox.removeEffect(effectId);
			if (effect.targetList.length == 1)
				delete effectList[effect.effectId];
			else
				effect.removeTarget(playerId);
			
		}
		
		/********************************************************************* END EFFECT HANDLING FUNCTIONS *************************************************************/
		
		/**************************************************************** ACTION CARD QUEUE FUNCTIONS ****************************************************/
		
		public function queueCardForDiscard(ac:ActionCardClip):Number {
			discardCounter++;
			discardList[discardCounter] = ac;
			return discardCounter;
		}
		public function unQueueCardForDiscard(ac:ActionCardClip):Number {
			var tmpArray:Dictionary = new Dictionary();
			var tmpOrder:Number = 0;
			var newIndex:Number = 1;
			for (var c = 1; c <= discardCounter; c++)
			{
				if (discardList[c].discardOrder < ac.discardOrder)
				{
					tmpArray[newIndex] = discardList[c];
					newIndex++;
				}
				else if (discardList[c].discardOrder > ac.discardOrder)
				{
					tmpOrder = discardList[c].discardOrder-1;
					discardList[c].updateOrder(tmpOrder);
					tmpArray[newIndex] = discardList[c];
					newIndex++;
				}
				
			}
			discardList = tmpArray;
			
			discardCounter--;
			
			return discardCounter;
			
		}
		
		
		public function queueCard(ac:ActionCardClip):Number {
			playCounter++;
			playedList[playCounter] = ac;
			return playCounter;
		}
		
		//Removes card from play queue
		public function unQueueCard(ac:ActionCardClip):Number {
			var tmpArray:Array = new Array();
			var tmpOrder:Number = 0;
			var newIndex:Number = 1;
			for (var c = 1; c <= playCounter; c++)
			{
				if (playedList[c].playOrder < ac.playOrder)
				{
					tmpArray[newIndex] = playedList[c];
					newIndex++;
				}
				else if (playedList[c].playOrder > ac.playOrder)
				{
					tmpOrder = playedList[c].playOrder-1;
					playedList[c].updateOrder(tmpOrder);
					tmpArray[newIndex] = playedList[c];
					newIndex++;
				}
				
			}
			playedList = tmpArray;
			
			playCounter--;
			
			return playCounter;
			
		}
		
		public function queueSub(pl:PlayerClip):Number {
			subList[pl.position] = pl;
			subCounter++;
			return subCounter;
		}
		
		public function unQueueSub(pl:PlayerClip):Number {
			delete subList[pl.position];
			subCounter--;
			return subCounter;
		}
		
		/**************************************************************** END ACTION CARD QUEUE FUNCTIONS ****************************************************/
		
		/******************************************************************** TARGETING FUNCTIONS ****************************************************************/
		
		public function updateActionTargets() {
			passTargets = new Array();
			dribbleTargets = new Array();
			var pos:Position;
			var posList:Array = engine.game.getTargetsForGameAction(GameAction.PASS);
			for each (pos in posList) {
				passTargets.push(engine.game.playerTeam.getPlayer(pos).instanceId.toString());
			}
			posList = engine.game.getTargetsForGameAction(GameAction.DRIBBLE);
			for each (pos in posList) {
				dribbleTargets.push(engine.game.playerTeam.getPlayer(pos).instanceId.toString());
			}
		}
		
		public function enterTargetMode(idList:Array, targetingCardId:String, ac:ActionCardClip = null, targetType:String = "player") {
			Logger.debug("UI > PlayArea entering target mode");
			targetModeActive = true;
			var checkInstanceId:int = 0;
			this.targetingCardId = targetingCardId;
			switch (targetType) {
				case "player":
					var pListLength:Number = fieldMc.playerList.length;
				
					for each (var pl in fieldMc.playerList) {
						checkInstanceId = idList.indexOf(pl.instanceId);
						//trace("CHECKINSTANCEID " + checkInstanceId);
						if (checkInstanceId < 0)
							pl.enterTargetMode(false);
						else
							pl.enterTargetMode(true);
					}
				break;
				case "effect":
					//Logger.debug("UI > PlayArea > Targeting effects");
					var effectTarget:String;
					for each (var effect:Effect in this.effectList) {
						//Logger.debug("UI > PlayArea > Checking effect " + effect.effectName + " ( " + effect.effectId + ") with targets " + effect.targetList + " in " + idList);
						//trace("CHECKING EFFECT ", effect.effectName, " ", effect.effectId, " WITH TARGETS ", effect.targetList, " IN ", idList);
						checkInstanceId = idList.indexOf(effect.effectId);
						//trace("CHECKINSTANCEID ", checkInstanceId);
						if (checkInstanceId < 0) { // Current Effect is NOT a valid target, disable all his icons from being targeted
							for each (effectTarget in effect.targetList) {
								fieldMc.playerList[effectTarget].effectBox.largeIconList[effect.effectId].enterTargetMode(false);
							}
						}
						else { // Current Effect is a valid target, enable all his icons for targeting
							for each (effectTarget in effect.targetList) {
								fieldMc.playerList[effectTarget].effectBox.largeIconList[effect.effectId].enterTargetMode(true);
							}
						}
					}
				break;
				case "card":
					showCardSelectionOverlay(idList);
				break;
			}
			
			
		}
		
		public function exitTargetMode(targetType:String = "player") {
			switch (targetType) {
				case "player":
					for each (var pl in fieldMc.playerList) {
						pl.exitTargetMode();
					}
				break;
			
				case "effect":
					//trace("TARGETING EFFECTS");
					var effectTarget:String;
					for each (var effect:Effect in this.effectList) {
						for each (effectTarget in effect.targetList) {
							fieldMc.playerList[effectTarget].effectBox.largeIconList[effect.effectId].exitTargetMode();
						}
					}
				break;
				case "card":
					hideCardSelectionOverlay();
				break;
			}
			this.targetingCardId = '';
			targetModeActive = false;
			if (engine.game.status != GameStatus.SUBSTITUTION)
				playMenu.showMenuButtons();
			else
				playMenu.setTargetingMessage("Select player to sub in");
			
		}
		
		public function setRoundActionTarget(pl:PlayerClip) {
			
			roundActionTarget = pl.position;
			
			logBox.dbgTextBox.text = logBox.dbgTextBox.text + "Round Action Target: " + pl.playerName + "\n";
			logBox.dbgTextBox.text = logBox.dbgTextBox.text + "Round Action Target Position: " + pl.position + "\n";
			
			var doubleArrow:Boolean = (roundAction == 'dribble');
			showActionAnimation(pl);
			showActionArrow(roundAction, fieldMc.playerList[ballHandler], pl);
			//fieldMc.addChild(arrowMc); 
			
			//frontObjects['actionArrow'] = arrowMc;
			playMenu.showMenuButtons();
			targetingCardId = '';
			exitTargetMode();
			
			if (roundActionTarget == 'f1' && fieldMc.playerList[ballHandler].position == 'd1')  {
				fieldMc.malusText.visible = true;
				fieldMc.malusText.y = -236;
				
			}
			else if (roundActionTarget == 'f2' && fieldMc.playerList[ballHandler].position == 'd2') {
				fieldMc.malusText.visible = true;
				fieldMc.malusText.y = 172;
			}
			else {
				fieldMc.malusText.visible = false;
			}
			
		}
		
		public function setRoundAction(action:String) {
			//showGoalAnimation(fieldMc.playerList[activePlayers[clientSide]]);
			clearActionArrow();
			roundAction = action;
			logBox.dbgTextBox.text = "Round Action: " + roundAction + "\n";
		}
		
		public function targetLockStatus(instanceId:String):Boolean {
			
			if ((this.targetingCardId == '')||(this.targetingCardId == instanceId)||(this.cardList[instanceId].cardZone != "hand"))
			{
				//trace('NO LOCKS');
				return false;
			}
			else 
				return true;
			
		}
		
		/******************************************************************** END TARGETING FUNCTIONS ****************************************************************/
		
		
		
		/******************************************************************** GAME OVER FUNCTIONS ****************************************************************/
		
		private function endGame():void {
			//Logger.debug("UI > PlayArea > endGame function called");
			playButton.removeEventListener(MouseEvent.CLICK, playButtonClickHandler);
			addChild(endGameScreen);
			endGameScreen.visible = true;
			timeline = new TimelineMax(new TweenMaxVars().onCompleteListener(slideInHandler));
			timeline.insert(TweenMax.from(endGameScreen, 2, new TweenMaxVars().y( -320).ease(Back.easeOut)));
			timeline.play();
		}
		
		private function slideInHandler(e:Event):void {
			var endMsg:String = '';
			switch (endCause) {
				case GameEndCause.PLAYER_WIN:
					endMsg = "YOU WIN!";
					break;
				case GameEndCause.OPPONENT_WIN:
					endMsg = "YOU LOSE!";
					break;
				case GameEndCause.DRAW:
					endMsg = "DRAW!";
					break;
			}
			endGameScreen.endGameText.text = endMsg;
		}
		
		/******************************************************************** END GAME OVER FUNCTIONS ****************************************************************/
		
		
		
		/******************************************************************** PHASE CHANGE FUNCTIONS ****************************************************************/
		
		
		
		private function updateUIStatus() {
			if (currentStatus != engine.game.status) {
				switch (currentStatus) {
					case GameStatus.SUBSTITUTION:
						exitSubstitutionPhase();
						break;
					case GameStatus.DISCARD:
						exitDiscardPhase();
						break;
					case GameStatus.PLAY:
						exitPlayPhase();
						break;
					case GameStatus.RESOLVE_PLAY:
						if (playerSkipsSolvePhase == true) {
							if (gameIsOver) {
								roundViewer.stopView();
								roundViewer = null;
								endGame();
							}
							else {
								nextTurnAvailable = false;
								playerSkipsSolvePhase = false;
								playerSkipsLog = false;
								exitSolvePhase();
							}
						}
						else if (playerSkipsLog) {
							roundViewer.skipToEnd();
							playButton.textLabel.text = 'Next Turn';
							return;
						}
						else {
							playSolvePhase();
							return;
						}
						
						//exitSolvePhase();
						
						break;
					default:
						exitPollingPhase();
						break;
				}
				currentStatus = engine.game.status;
				Logger.debug("UI > Entering" + engine.game.status.name.toString() + "phase");
				
				switch (engine.game.status) {
					case GameStatus.SUBSTITUTION:
						setupSubstitutionPhase();
						break;
					case GameStatus.DISCARD:
						setupDiscardPhase();
						break;
					case GameStatus.PLAY:
						setupPlayPhase();
						break;
					case GameStatus.RESOLVE_PLAY:
						setupSolvePhase();
						break;
					case GameStatus.DONE:
						break;
					default:
						setupPollingPhase();
						break;
				}
			}
		}
		
		public function setupPollingPhase() {
			//fieldMc.screen.visible = true;
			playMenu.setTargetingMessage("Waiting for opponent...");
			playButton.visible = false;
		}
		
		public function exitPollingPhase() {
			//fieldMc.screen.visible = false;
			playMenu.setTargetingMessage("");
			playButton.visible = true;
		}
		
		public function setupSubstitutionPhase() {
			clearActionArrow();
			fieldMc.update();
			var ac:ActionCardClip;
			for each(ac in handCardList) {
				ac.visible = false;
			}
			playMenu.setTargetingMessage("Select players to sub in");
			playButton.textLabel.text = 'SUB';
			updateBallHandler();
			
			fieldMc.getPlayerAtPos("sub_df", clientSide).visible = true;
			fieldMc.getPlayerAtPos("sub_mf", clientSide).visible = true;
			fieldMc.getPlayerAtPos("sub_fw", clientSide).visible = true;
		}
		
		public function exitSubstitutionPhase() {
			/*
			var ac:ActionCardClip;
			for each(ac in handCardList) {
				ac.visible = true;
			}
			*/
			var pl:PlayerClip;
			for each (pl in fieldMc.playerList)
				pl.filters = [];
			fieldMc.getPlayerAtPos("sub_df", clientSide).visible = false;
			fieldMc.getPlayerAtPos("sub_mf", clientSide).visible = false;
			fieldMc.getPlayerAtPos("sub_fw", clientSide).visible = false;
		}
		
		public function setupDiscardPhase() {
			var ac: ActionCardClip;
			for each(ac in handCardList) {
				ac.visible = true;
				ac.hidePlayabilitySign();
			}
			
			clearActionArrow();
			fieldMc.update();
			updateBallHandler();
			updateActivePlayers();
			fieldMc.screen.visible = true;
			fieldMc.addChild(fieldMc.screen);
			playMenu.setTargetingMessage("Select cards to discard");
			playButton.textLabel.text = 'DISCARD';
		}
		
		public function exitDiscardPhase() {
			fieldMc.screen.visible = false;
			var ac:ActionCardClip;
			for each (ac in discardList) {
				ac.isQueuedForDiscard = false;
				ac.discardOrder = 0;
				ac.playOrderBox.text = "";
				ac.loaderLarge.filters = [];
				
				
			}
			
			discardList = new Dictionary();
			discardCounter = 0;
		}
		
		public function exitPlayPhase() {
			var ac:ActionCardClip;
			for each (ac in playedList) {
				ac.isPlayed = false;
				ac.playOrder = 0;
				ac.playOrderBox.text = "";
				ac.loaderLarge.filters = [];
				if (ac.hasTarget == true)
					ac.targetId = null;
				
			}
			for each (var currentPl:PlayerClip in fieldMc.playerList)
				currentPl.zoomOut(new MouseEvent("click"));
			playedList = new Array();
			playCounter = 0;
			roundActionTarget = '';
			roundAction = '';
		}
		
		public function setupPlayPhase() {
			playMenu.showMenuButtons();
			playMenu.unsetFilters();
			refreshHand();
			updateActionTargets();
			refreshCardCounters();
			playButton.textLabel.text = 'PLAY';
		}
		
		/**************************************************
		* fieldMc.screen blocks access to all play elements
		* both active players are zoomed in and locked
		**************************************************/
		public function setupSolvePhase() {
			
			fieldMc.screen.visible = true;
			fieldMc.addChild(fieldMc.screen);
			
			playMenu.setTargetingMessage("Waiting for opponent...");
			var ac:ActionCardClip;
			for each(ac in handCardList) {
				ac.visible = false;
			}
			playButton.textLabel.text = 'Skip';
			playButton.visible = false;
		}
		
		public function playSolvePhase() {
			
			if (!roundViewer) {
				solveOverlay.slideIn();
				nextTurnAvailable = true;
				playButton.visible = true;
				playMenu.setTargetingMessage("Round solved");
				var turn:GameTurn = engine.game.turns.getLastTurn();
				
				roundViewer = new RoundViewer(turn, this);
				roundViewer.start();
			}
		}
		
		public function exitSolvePhase() {
			roundViewer.stopView();
			roundViewer.clearActionCards();
			roundViewer = null;
			solveOverlay.slideOut();
			refreshHand();
			fieldMc.screen.visible = false;
			fieldMc.malusText.visible = false;
			for each (var currentPl:PlayerClip in fieldMc.playerList) {
				currentPl.unlockFromSolvePhase();
				currentPl.hideScore();
			}
			scoreboard.roundCounterBox.text = "Round " + engine.game.turn;
			scoreboard.homeScoreBox.text = engine.game.homeTeam.score.toString();
			scoreboard.awayScoreBox.text = engine.game.awayTeam.score.toString();
			clientRole = engine.game.playerTeam.role;
			maxPlayables = engine.game.playerTeam.cards.maxPlayable;
			refreshCardCounters();
			
			playMenu.setTargetingMessage("");
			logBox.dbgTextBox.text = '';
			clearActionArrow();
			
		}
		
		
		/******************************************************************** END PHASE CHANGE FUNCTIONS ****************************************************************/
		
		/******************************************************************** VISUAL UI FUNCTIONS ****************************************************************/
		
		private function showActionAnimation(pl:PlayerClip = null):void {
			timeline = new TimelineMax();
			
			switch (roundAction) {
				case 'dribble':
					timeline = fieldMc.animatePlayerToPos(fieldMc.playerList[activePlayers[clientSide]], pl.position);
					break;
				case 'pass':
					fieldMc.addChild(fieldMc.playerList[activePlayers[clientSide]]);
					var targetPoint:Point = getRelativePlayerPosition(activePlayers[clientSide], pl.instanceId);
					ball.animatePassTo(targetPoint);
					break;
			}
			timeline.play();
		}
		
		private function animateCardToHand(ac:ActionCardClip, delayModifier:uint = 0):TimelineMax {
			var tl:TimelineMax = new TimelineMax();
			
			tl.insert(TweenMax.from(ac, 0.75, new TweenMaxVars().autoAlpha(0).x(580).delay((ac.cardOrder-delayModifier) * 0.25).ease(Quad.easeIn)));
			
			return tl;
		}
		
		public function showGoalAnimation(pl:PlayerClip):void {
			
			//reset positions
			imgGoal.x 			= -210;
			imgGoal.y 			= 90;
			imgGoal.visible 	= true;
			imgGoal.alpha		= 1;
			imgGoal.filters		= [];
			imgScored.x 		= 1160;
			imgScored.y 		= 490;
			imgScored.visible 	= true;
			imgScored.alpha		= 1;
			imgScored.filters	= [];
			
			timeline = new TimelineMax();
			timeline.insert(new TweenMax(imgGoal, 2, new TweenMaxVars().bezier([ { x: 630, y:290 }, { x: 430, y:190 } ]).ease(Back.easeOut)));
			timeline.insert(new TweenMax(imgScored, 2, new TweenMaxVars().bezier([{ x: 228, y:190 }, { x: 428, y:290 } ]).ease(Back.easeOut)));
			
			var tArray:Array = new Array();
			tArray.push(new TweenMax(imgGoal, 1, new TweenMaxVars().blurFilter(30, 30).autoAlpha(0).ease(Back.easeIn)));
			tArray.push(new TweenMax(imgScored, 1, new TweenMaxVars().blurFilter(30, 30).autoAlpha(0).ease(Back.easeIn)));
			
			timeline.appendMultiple(tArray);
			
			timeline.play();
		}
		
		public function refreshCardCounters():void {
			
			homeHandMC.numBox.text = engine.game.homeTeam.cards.cardCount;
			awayHandMC.numBox.text = engine.game.awayTeam.cards.cardCount;
			homeDeckMC.numBox.text = engine.game.homeTeam.cards.deckCardCount;
			awayDeckMC.numBox.text = engine.game.awayTeam.cards.deckCardCount;
			/*
			Logger.debug("UI > PLAYAREA > Home Deck Cards: " + engine.game.homeTeam.cards.deckCardCount.toString());
			Logger.debug("UI > PLAYAREA > Away Deck Cards: " + engine.game.awayTeam.cards.deckCardCount.toString());
			*/
			homeGraveMC.numBox.text = engine.game.homeTeam.cards.graveyardCardCount;
			awayGraveMC.numBox.text = engine.game.awayTeam.cards.graveyardCardCount;
			
		}
		
		public function refreshHand(animateCardsOut:Boolean = false):void {
			var gac:GameActionCard;
			var ac:ActionCardClip;
			timeline = new TimelineMax();
			var delayDelta:uint = 0;
			for (var instanceId in handCardList) {
				ac = handCardList[instanceId];
				//Logger.debug("UI > checking " + ac.name + " (" + instanceId + ")");
				if (!engine.game.playerTeam.cards.hasCardInHand(ac.instanceId)) {
					//Logger.debug("UI > " + ac.name + " no longer in hand");
					removeCardFromHand(ac);
				}
				else {
					delayDelta++;
					ac.setPlayability();
					ac.unsetNewCardGlow();
					if (ac.hasTarget) {
						Logger.debug("UI > Refreshing targets for " + ac.name);
						ac.loadTargets();
					}
					
					//Logger.debug("UI > " + ac.name + " still in hand");
				}
			}
			reorderCards();
			for each (gac in engine.game.playerTeam.cards.hand) {
				if (handCardList[gac.instanceId.toString()]) {
					
				}
				else {
					ac = new ActionCardClip(gac, this, handCounter);
					addCardToHand(ac, true);
					timeline.insert(animateCardToHand(ac, delayDelta));
				}
				
			}
			timeline.play();
		}
		
		public function reorderCards():void {
			var newOrder:uint = 1;
			var currentAc:ActionCardClip;
			for (var instanceId in handCardList) {
				currentAc = handCardList[instanceId];
				currentAc.cardOrder = newOrder;
				setChildIndex(currentAc, newOrder);
				currentAc.x = (currentAc.cardOrder - 1)*70 + ac1.x;
				newOrder++;
			}
		}
		
		public function updateBallHandler(newBallHandler:String = ""):void {
			if (newBallHandler == '') {
				if (engine.game.isPlayerAttacking) {
					newBallHandler = engine.game.playerActivePlayerCard.instanceId.toString();
				}
				else {
					newBallHandler = engine.game.opponentActivePlayerCard.instanceId.toString();
				}
			}
			if (newBallHandler != ballHandler) {
				fieldMc.playerList[ballHandler].unsetAsBallHandler();
				ballHandler = newBallHandler;
				fieldMc.playerList[ballHandler].setAsBallHandler(ball);
			}
		}
		
		public function updateActivePlayers():void {
			if (engine.game.playerActivePlayerCard.instanceId.toString() != activePlayers[clientSide]) {
				fieldMc.playerList[activePlayers[clientSide]].unsetAsActive();
				activePlayers[clientSide] = engine.game.playerActivePlayerCard.instanceId.toString();
				fieldMc.playerList[activePlayers[clientSide]].setAsActive();
			}
			if (engine.game.opponentActivePlayerCard.instanceId.toString() != activePlayers[oppSide]) {
				activePlayers[oppSide] = engine.game.opponentActivePlayerCard.instanceId.toString();
			}
		}
		
		public function showCardSelectionOverlay(idList:Array):void {
			
			addChild(overlay);
			for each (var instanceId:String in idList) {
				if (homeGraveOverlay.cardList[instanceId]) {
					//trace("Card", instanceId, "found");
					homeGraveOverlay.cardList[instanceId].addToCardSelectionOverlay();
				}
			}
		}
		
		public function hideCardSelectionOverlay():void {
			overlay.clearOverlay();
			removeChild(overlay);
		}
		
		public function toggleHomeGraveOverlay(e:MouseEvent):void {
			
			if (homeGraveOverlay.visible == true) {
				homeGraveOverlay.visible = false;
			}
			else {
				if (awayGraveOverlay.visible == true)
					awayGraveOverlay.visible = false;
				homeGraveOverlay.visible = true;
			}
		}
		
		public function toggleAwayGraveOverlay(e:MouseEvent):void {
			
			if (awayGraveOverlay.visible == true) {
				awayGraveOverlay.visible = false;
			}
			else {
				if (homeGraveOverlay.visible == true)
					homeGraveOverlay.visible = false;
				awayGraveOverlay.visible = true;
			}
		}
		
		function highlightPlayer(pl:PlayerClip):void {
			//trace("HIGHLIGHTING ",pl.playerName);
			var e:MouseEvent = new MouseEvent('rollOver');
			//e.target.name = 'smallImage';
			pl.zoomIn(e);
		}
		
		function stopHighlightingPlayer(pl:PlayerClip) {
			var e:MouseEvent = new MouseEvent('rollOut');
			//e.target.name = 'smallImage';
			pl.zoomOut(e);
		}
		
		function clearActionArrow():void {
			if (arrowMc != null) {
				//trace("REMOVING ARROW");
				fieldMc.removeChild(arrowMc);
				delete frontObjects['actionArrow'];
				arrowMc = null;
			}
		}
		
		function showActionArrow(action:String, pFrom:PlayerClip, pTo:PlayerClip):void {
			clearActionArrow();
			var doubleArrow:Boolean = (action == 'dribble');
			arrowMc = getActionArrow(pFrom, pTo, doubleArrow);
			fieldMc.addChild(arrowMc); 
				
			frontObjects['actionArrow'] = arrowMc;
			
			
		}
		
		function getActionArrow(pFrom:PlayerClip, pTo:PlayerClip, twoWay:Boolean = false):MovieClip {
			
			var from:Point = new Point(int(pFrom.x), int(pFrom.y));
			var to:Point = new Point(int(pTo.x), int(pTo.y));
			
			if (!twoWay)
				return createArrow(from, to);
			else {
				var a:MovieClip = new MovieClip();
				if(from.y > to.y){
					from.y = from.y - 10;
					to.y = to.y - 10;
					a.addChild(createArrow(from, to));
					from.y = from.y + 20;
					to.y = to.y + 20;
					a.addChild(createArrow(to, from));
				}
				else{
					from.y = from.y + 10;
					to.y = to.y + 10;
					a.addChild(createArrow(from, to));
					from.y = from.y - 20;
					to.y = to.y - 20;
					a.addChild(createArrow(to, from));
				}
				
				return a;
			}
		}
		
		public function getPlayerContainer(pl:PlayerClip):CardHolder {
			var childName:String = fieldMc.playerList[pl.instanceId].position + "_" + fieldMc.playerList[pl.instanceId].side;
			var targetContainer:CardHolder = CardHolder(fieldMc.getChildByName(childName));
			
			return targetContainer;
		}
		
		public function restoreFrontObjects():void {
			
			for each(var clip:MovieClip in frontObjects)
			{
				fieldMc.addChild(clip);
			}
		}
		
		function createArrow(from:Point, to:Point):MovieClip{
			var a:MovieClip = new MovieClip();
			var b:MovieClip = new MovieClip();
			
			var g:Graphics = a.graphics;
			var pointTo:String;
			if (from.x == to.x)
			{
				if(from.y < to.y){
						to.y -= 10;
						pointTo = "top";
				}
				else{
						to.y += 10;
						pointTo = "bottom";
				}
			}
			else if (from.x < to.x)
				pointTo = "right";
			else
				pointTo = "left";
			a.x = a.y = 0;
			g.lineStyle(4, 0x000000, 1);
			g.moveTo(from.x, from.y);
			//g.lineTo(from.x, (to.y+from.y)/2);
			//g.lineTo(to.x, (to.y+from.y)/2);
			//g.lineTo(to.x, to.y);
			
			//var xDistance:uint = (to.x - from.x)/2;
			var controlX:int = from.x;
			var controlY:int = to.y;
			
			g.curveTo(controlX, controlY, to.x, to.y);
			//g.lineTo(to.x, to.y);
			drawTriangle(to, b.graphics, pointTo);
			a.addChild(b);
			return a;
		}
		
		function drawTriangle(pt:Point, g:Graphics, pointTo:String):void{
				
				switch (pointTo) {
					case "top":
					break;
					case "bottom":
					break;
					case "left":
					break;
					case "right":
					break;
				}
				
				
				if ((pointTo == "top")||(pointTo == "bottom")) {
					pt.y = pt.y +(!(pointTo == "top")?-10:10);
					g.moveTo(pt.x-10, pt.y);
					g.lineStyle(4, 0x000000, 1);
					//g.beginFill(0x000000);
					//g.lineTo(pt.x-10, pt.y);
					g.lineTo(pt.x, pt.y+(!(pointTo == "top")?-15:15));
					g.lineTo(pt.x+10, pt.y);
					//g.lineTo(pt.x, pt.y);
					//g.endFill();
				}
				else {
					pt.x = pt.x +(!(pointTo == "left")?-10:10);
					g.moveTo(pt.x, pt.y-10);
					//g.beginFill(0x000000);
					g.lineStyle(4, 0x000000, 1);
					//g.lineTo(pt.x, pt.y-10);
					g.lineTo(pt.x+(!(pointTo == "left")?15:-15), pt.y);
					g.lineTo(pt.x, pt.y+10);
					//g.lineTo(pt.x, pt.y);
					//g.endFill();
				}
				
		}
		
		/******************************************************************** MISCELLANEOUS FUNCTIONS ****************************************************************/
		
		public function getRelativePlayerPosition(basePlayerId:String, targetPlayerId:String):Point {
			
			var targetPoint:Point = new Point(fieldMc.playerList[targetPlayerId].x, fieldMc.playerList[targetPlayerId].y);
			targetPoint = fieldMc.localToGlobal(targetPoint);
			targetPoint = fieldMc.playerList[basePlayerId].globalToLocal(targetPoint);
			return targetPoint;
		}
		
		public function attachMenu():void {
			playMenu.visible = true;
			playMenu.init(fieldMc.playerList[activePlayers[clientSide]].position, this);
		
		}

		public function dispose():void {
			fieldMc.dispose();
			removeChild(fieldMc);
			fieldMc = null;
			
			timeline = null;
			for each (var ac:ActionCardClip in cardList) {
				ac.dispose();
				try {
					removeChild(ac);
				}
				catch (e:Error) {
					
				}
				ac = null;
				
			}
			
		}
		
	}
	
}
